home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / SCSI Samples 1.0 / SCSI Inquiry Samples ƒ / SCSI Inquiry (Simple) 06⁄07 ƒ / Src / SCSIInquiry.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  7.4 KB  |  260 lines  |  [TEXT/KAHL]

  1. /*                                SCSIInquiry.c                            */
  2. /*
  3.  * SCSIInquiry.c
  4.  * Copyright © 1994 Apple Computer Inc. All rights reserved.
  5.  * This is a minimal sample to illustrate the Old SCSI Manager.
  6.  */
  7. #include "SCSIInquiry.h"
  8.  
  9. #ifndef THINK_C                /* MPW includes            */
  10. #include <Errors.h>
  11. #include <Script.h>
  12. #include <Types.h>
  13. #include <Files.h>
  14. #include <Resources.h>
  15. #include <QuickDraw.h>
  16. #include <Fonts.h>
  17. #include <Events.h>
  18. #include <Windows.h>
  19. #include <ToolUtils.h>
  20. #include <Memory.h>
  21. #include <Menus.h>
  22. #include <Lists.h>
  23. #include <Printing.h>
  24. #include <Dialogs.h>
  25. #include <StandardFile.h>
  26. #endif
  27.  
  28. #include <SCSI.h>
  29.  
  30. unsigned short            gTargetDevice = 0;    /* Using device at ID = 0    */
  31.  
  32. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  33.  * SCSI Definitions
  34.  */
  35. #define    kScsiStatusGood            0x00        /* Normal completion        */
  36. #define    kScsiCmdInquiry            0x12        /* Device inquiry command    */
  37.  
  38. struct SCSI_6_Byte_Command {                /* Six-byte command            */
  39.     unsigned char        opcode;                /*  0                        */
  40.     unsigned char        lbn3;                /*  1 lbn in low 5            */
  41.     unsigned char        lbn2;                /*  2                        */
  42.     unsigned char        lbn1;                /*  3                        */
  43.     unsigned char        len;                /*  4                        */
  44.     unsigned char        ctrl;                /*  5                        */
  45. };
  46. typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
  47.  
  48. struct SCSI_Inquiry_Data {                    /* Inquiry returns this        */
  49.     unsigned char        devType;            /*  0 Device type,            */
  50.     unsigned char        devTypeMod;            /*  1 Device type modifier    */
  51.     unsigned char        version;            /*  2 ISO/ECMA/ANSI version    */
  52.     unsigned char        format;                /*  3 Response data format    */
  53.     unsigned char        length;                /*  4 Additional Length        */
  54.     unsigned char        reserved5;            /*  5 Reserved                */
  55.     unsigned char        reserved6;            /*  6 Reserved                */
  56.     unsigned char        flags;                /*  7 Capability flags        */
  57.     unsigned char        vendor[8];            /*  8-15 Vendor-specific    */
  58.     unsigned char        product[16];        /* 16-31 Product id            */
  59.     unsigned char        revision[4];        /* 32-35 Product revision    */
  60.     unsigned char        vendorSpecific[20]; /* 36-55 Vendor stuff        */
  61.     unsigned char        moreReserved[40];    /* 56-95 Reserved            */
  62. };
  63. typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
  64.  
  65. SCSI_Inquiry_Data            gInquiryData;    /* Inquiry data goes here    */
  66. unsigned long                gInquirySize;    /* Number of bytes read        */
  67.  
  68. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  69.  * gSCSICommand is the command that we send to the device.
  70.  */
  71. SCSI_6_Byte_Command            gSCSICommand = {
  72.         kScsiCmdInquiry,                    /* Command                    */
  73.         0,                                    /* LBN 3 -- unused            */
  74.         0,                                    /* LBN 2 -- unused            */
  75.         0,                                    /* LBN 1 -- unused            */
  76.         sizeof (SCSI_Inquiry_Data),            /* Returned buffer length    */
  77.         0                                    /* Flags -- must be zero    */
  78.     };
  79.  
  80. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  81.  * gRequestTIB defines the buffer that SCSIRead reads into. Because
  82.  * the Inquiry command can return a variable-length record, we use a
  83.  * TIB with single-byte transfers and an internal counter so we can
  84.  * recover the actual transfer length. The four tib values are used
  85.  * as follows:
  86.  *        scInc...    Move one byte from the device to the buffer address
  87.  *                    and increment the buffer address pointer.
  88.  *        scAdd...    Add one to gInquirySize -- this gives the actual
  89.  *                    number of bytes transfered.
  90.  *        scLoop        Continue processing TIB instructions at the start
  91.  *                    until the maximum number of loops have been done.
  92.  *        scStop        End of the TIB.
  93.  * Note that this is an extremely inefficient TIB and should only be
  94.  * used for polled "administrative" requests that return a variable-
  95.  * length buffer.
  96.  */
  97. SCSIInstr                    gRequestTIB[] = {
  98.     { scInc,    0, 1 },
  99.     { scAdd,    0, 1 },
  100.     { scLoop,    (-2 * sizeof (SCSIInstr)),    sizeof (SCSI_Inquiry_Data)    },
  101.     { scStop,    0,                                0 }
  102. };
  103.  
  104. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  105.  * Local functions and administrative variables.
  106.  */
  107. #ifdef __powerc
  108. QDGlobals                qd;
  109. #endif
  110.  
  111. void                        DisplayError(
  112.         OSErr                    errorStatus
  113.     );
  114. OSErr                        DoSCSICommand(
  115.         unsigned short            targetID,
  116.         const Ptr                scsiCommand,
  117.         SCSIInstr                *requestTIB
  118.     );
  119. void                        DisplaySCSIInquiry(
  120.         long                    actualTransferCount
  121.     );
  122.  
  123. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  124.  * Local functions and administrative variables.
  125.  */
  126. void
  127. main(void)
  128. {
  129.         short                    i;
  130.         OSErr                    status;
  131.         OSErr                    completionStatus;
  132.         EventRecord                eventRecord;
  133.         long                    actualTransferCount;
  134.         unsigned long            watchdog;
  135.         short                    stsByte;
  136.         short                    msgByte;
  137.             
  138.         MaxApplZone();        
  139.         InitGraf(&qd.thePort);
  140.         InitFonts();
  141.         InitWindows();
  142.         InitMenus();
  143.         TEInit();
  144.         InitDialogs(0);
  145.         for (i = 0; i < 3; i++)
  146.             EventAvail(everyEvent, &eventRecord);
  147.         gRequestTIB[0].scParam1 = (unsigned long) &gInquiryData;
  148.         gRequestTIB[1].scParam1 = (unsigned long) &gInquirySize;
  149.         /*
  150.          * This is a simplified form of the "Get Bus" protocol.
  151.          */
  152.         watchdog = TickCount() + 300;
  153.         while ((status = SCSIGet()) != noErr && TickCount() < watchdog)
  154.             ;
  155.         if (status == noErr)
  156.             status = SCSISelect(gTargetDevice);
  157.         if (status == noErr) {
  158.             status = SCSICmd((Ptr) &gSCSICommand, sizeof gSCSICommand);
  159.             if (status == noErr)
  160.                 status = SCSIRead((Ptr) gRequestTIB);
  161.             completionStatus = SCSIComplete(&stsByte, &msgByte, 5 * 60);
  162.             if (status == noErr && completionStatus != noErr)
  163.                 status = completionStatus;
  164.             if (status == scPhaseErr && stsByte == kScsiStatusGood)
  165.                 status = noErr;
  166.             if (status == noErr && stsByte != kScsiStatusGood)
  167.                 status = ioErr;
  168.         }
  169.         /*
  170.          * Since the Device Inquiry command can return a variable-length
  171.          * record, we need to obtain the actual number of bytes that
  172.          * were read. There are two algorithms we can use here, that
  173.          * should result in the same data:
  174.          *    Since tib[0].scOpcode was scInc, tib[0].scParam1 will point to
  175.          *        the next byte to store. We can subtract the original buffer
  176.          *        pointer from that value to get the actual count.
  177.          *    Since tib[1].scOpcode was scAdd, gInquirySize will have the
  178.          *        actual count.
  179.          *    One or another of these two techniques can be used for this
  180.          *    type of data.
  181.          */
  182.         actualTransferCount =
  183.             gRequestTIB[0].scParam1 - (unsigned long) &gInquiryData;
  184.         if (actualTransferCount != gInquirySize)
  185.             DisplayError(paramErr);
  186.         if (status != noErr)
  187.             DisplayError(status);
  188.         DisplaySCSIInquiry(actualTransferCount);
  189.         ExitToShell();
  190. }
  191.  
  192.  
  193. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  194.  * Display the inquiry result.
  195.  */
  196. static void
  197. StoreString(
  198.         const unsigned char        *textPtr,
  199.         Size                    textLength,
  200.         StringPtr                result
  201.     )
  202. {
  203.         register short            i;
  204.         
  205.         for (i = textLength; i > 0; --i) {
  206.             if (textPtr[i - 1] != ' ' && textPtr[i - 1] != 0)
  207.                 break;
  208.         }
  209.         BlockMove(textPtr, &result[1], i);
  210.         result[0] = i;
  211. }
  212.  
  213. void
  214. DisplaySCSIInquiry(
  215.         long                    actualTransferCount
  216.     )
  217. {
  218.         Str255                    inquirySize;
  219.         Str255                    vendorName;
  220.         Str255                    productName;
  221.         Str255                    revisionLevel;
  222.         
  223.         NumToString(actualTransferCount, inquirySize);
  224.         StoreString(
  225.             gInquiryData.vendor,
  226.             sizeof gInquiryData.vendor,
  227.             vendorName
  228.         );
  229.         StoreString(
  230.             gInquiryData.product,
  231.             sizeof gInquiryData.product,
  232.             productName
  233.         );
  234.         StoreString(
  235.             gInquiryData.revision,
  236.             sizeof gInquiryData.revision,
  237.             revisionLevel
  238.         );
  239.         ParamText(inquirySize, vendorName, productName, revisionLevel);
  240.         NoteAlert(ALRT_Info, NULL);
  241. }
  242.  
  243.  
  244. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  245.  * Display an error alert.
  246.  */
  247. void
  248. DisplayError(
  249.         OSErr                    errorStatus
  250.     )
  251. {
  252.         Str255                    work;
  253.         
  254.         NumToString(errorStatus, work);
  255.         ParamText(work, "\p", "\p", "\p");
  256.         InitCursor();
  257.         StopAlert(ALRT_Error, NULL);
  258. }
  259.  
  260.